package com.k8.common.ioc.injectorImpl;

import com.k8.common.aware.ExtensionAccessorAware;
import com.k8.common.factroy.instance.InstanceStrategyFactory;
import com.k8.common.factroy.loader.ExtensionAccessor;
import com.k8.common.factroy.loader.ExtensionLoader;
import com.k8.common.util.StrUtil;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
public class SpiInstanceStrategyFactoryInjector extends AbstractInstanceStrategyFactoryInjector implements ExtensionAccessorAware {
    @Override
    public void synJudge(Map<String, Object> relyBeanNames) {
        InstanceStrategyFactory instanceStrategyFactory = this.extensionAccessor.getInstanceStrategyFactory();
        synJudge0(relyBeanNames, instanceStrategyFactory);
    }

    ExtensionAccessor extensionAccessor;

    @Override
    public void setExtensionAccessor(ExtensionAccessor extensionAccessor) {
        this.extensionAccessor = extensionAccessor;
    }


    public boolean inject(Map<String, Object> relyBeanMaps, Object instance, Field field) {
        try {
            if (field.getAnnotation(Resource.class) != null) {
                Resource annotation = field.getAnnotation(Resource.class);
                String name = annotation.name();
                Class<?> type = field.getType();
                if (!type.isInterface()) return false;
                ExtensionLoader<?> extensionLoader = extensionAccessor.getExtensionLoader(type);
                if (extensionLoader == null) {
                    return false;
                }
                Object extension = null;
                String injectName = null;
                if (!name.isEmpty()) {
                    extension = extensionLoader.getExtensionToInject(name);
                    if (extension != null) {
                        injectName = name;
                    }
                } else {
                    String defaultName = extensionLoader.getDefaultName();
                    if (StrUtil.isNotEmpty(defaultName)) {
                        extension = extensionLoader.getExtensionToInject(defaultName);
                    }
                    if (extension == null) {
                        String simpleClassName = type.getName();//全限定名获取ServiceLoader加载的
                        extension = extensionLoader.getExtensionToInject(simpleClassName);
                        if (extension != null) {
                            injectName = simpleClassName;
                        }
                    } else {
                        injectName = defaultName;
                    }
                }
                if (extension == null) {
                    return false;
                }
                field.setAccessible(true);
                field.set(instance, extension);
                relyBeanMaps.put(injectName, extension);
                return true;
            }
            return false;
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public boolean needInject(Field field) {
        return field.isAnnotationPresent(Resource.class) && field.getType().isInterface();
    }

    /**
     * 参数clazz是一个接口类，需要判断返回名的类型是否是它的子类
     */
    private <T> T getBean(ExtensionLoader<T> extensionLoader, final Map<String, SafeObjectHolder> relyBeanMaps, Class<? extends T> clazz, String name, boolean registry) {
        if (extensionLoader == null) return null;
        Class<? extends T> extensionClass = extensionLoader.getExtensionClass(name);
        if (null == extensionClass || !extensionClass.isAssignableFrom(clazz)) return null;
        InstanceStrategyFactory instanceStrategyFactory = extensionAccessor.getInstanceStrategyFactory();
        T extension;
        if (registry) {
            extension = instanceStrategyFactory.getBeanOrRegistryToInject(clazz, name);
        } else {
            extension = instanceStrategyFactory.getBean(clazz, name);
        }
        if (extension != null) {
            relyBeanMaps.put(name, new SafeObjectHolder(extension));
        }
        return extension;
    }

    @Override
    public <T> T getBean(final Map<String, SafeObjectHolder> relyBeanMaps, Class<T> clazz, String name) {
        ExtensionLoader<T> extensionLoader = extensionAccessor.getExtensionLoader(clazz);
        return getBean(extensionLoader, relyBeanMaps, clazz, name, false);
    }

    @Override
    public <T> T getBean(final Map<String, SafeObjectHolder> relyBeanMaps, Class<T> clazz) {
        ExtensionLoader<T> extensionLoader = extensionAccessor.getExtensionLoader(clazz);
        if (extensionLoader == null) return null;
        String name = extensionLoader.getDefaultName();
        if (!StrUtil.isNotEmpty(name)) return null;
        return getBean(extensionLoader, relyBeanMaps, clazz, name, false);
    }

    @Override
    public <T> T getBeanOrRegistry(final Map<String, SafeObjectHolder> relyBeanMaps, Class<T> clazz, String name) {
        ExtensionLoader<T> extensionLoader = extensionAccessor.getExtensionLoader(clazz);
        return getBean(extensionLoader, relyBeanMaps, clazz, name, true);
    }

    @Override
    public <T> T getBeanOrRegistry(final Map<String, SafeObjectHolder> relyBeanMaps, Class<T> clazz) {
        ExtensionLoader<T> extensionLoader = extensionAccessor.getExtensionLoader(clazz);
        if (extensionLoader == null) return null;
        String name = extensionLoader.getDefaultName();
        if (!StrUtil.isNotEmpty(name)) return null;
        return getBean(extensionLoader, relyBeanMaps, clazz, name, true);
    }

    //返回所有的Extension,默认注册，不同于BeanFactory默认不注册
    @Override
    public <T> List<T> getAllBeans(Map<String, SafeObjectHolder> relyBeanMaps, Class<T> clazz) {
        ExtensionLoader<T> extensionLoader = extensionAccessor.getExtensionLoader(clazz);
        if (extensionLoader == null) return null;
        List<String> allNames = extensionLoader.getAllNames();
        return allNames.stream().map(name -> {
            return getBean(extensionLoader, relyBeanMaps, clazz, name, true);
        }).collect(Collectors.toList());
    }

    @Override
    public <T> T getAdaptive(Map<String, SafeObjectHolder> relyBeanMaps, Class<T> clazz) {
        ExtensionLoader<T> extensionLoader = extensionAccessor.getExtensionLoader(clazz);
        return extensionLoader.getAdaptiveExtensionToInject();
    }
}
